package com.zlsf.publish.local;


import com.zlsf.codec.AudioCodec;
import com.zlsf.entity.Media;
import com.zlsf.entity.MediaEncoding;
import com.zlsf.flv.FlvEncoder;
import com.zlsf.util.ByteHolder;
import io.vertx.core.Vertx;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ChannelLocal {

  String tag;
  ByteHolder buffer;
  AudioCodec audioCodec;
  FlvEncoder flvEncoder;
  private long firstTimestamp = -1;
  private Vertx vertx;
  //private VideoPublisher publisher;


  public ChannelLocal(String tag, Vertx vertx) {
    this.tag = tag;
    this.vertx = vertx;
    this.flvEncoder = new FlvEncoder(true, true);
    this.buffer = new ByteHolder(2048 * 100);
    //this.publisher = new VideoPublisher(tag, vertx);
  }


  public void writeAudio(long timestamp, int pt, byte[] data) {
    if (audioCodec == null) {
      audioCodec = AudioCodec.getCodec(pt);
      log.info("audio codec: {}", MediaEncoding.getEncoding(Media.Type.Audio, pt));
    }
  }


  public void writeVideo(long sequence, long timeoffset, int payloadType, byte[] h264) {
    if (firstTimestamp == -1) firstTimestamp = timeoffset;
    this.buffer.write(h264);

    while (true) {
      byte[] nalu = readNalu();
      if (nalu == null) break;
      if (nalu.length < 4) continue;

      byte[] flvTag = this.flvEncoder.write(nalu, (int) (timeoffset - firstTimestamp));
      if (flvTag == null) continue;
      // this.publisher.onVideoData(timeoffset, flvTag, this.flvEncoder);
    }
  }


  public void close() {
    //this.publisher.close();
  }

  private byte[] readNalu() {
    for (int i = 0; i < buffer.size() - 3; i++) {
      int a = buffer.get(i + 0) & 0xff;
      int b = buffer.get(i + 1) & 0xff;
      int c = buffer.get(i + 2) & 0xff;
      int d = buffer.get(i + 3) & 0xff;
      if (a == 0x00 && b == 0x00 && c == 0x00 && d == 0x01) {
        if (i == 0) continue;
        byte[] nalu = new byte[i];
        buffer.sliceInto(nalu, i);
        return nalu;
      }
    }
    return null;
  }


}
